雖然在JSXGraph中可以輕易建立button、chebox、label…等元件,但是這些元件會在畫板內,因此排版並不方便,也會干擾幾何元素的呈現。今天我們將昨天的按鈕從JSXGraph的容器獨立出來,另外建立這些按鈕的容器。因此今天我們會學習Html的基本觀念、DOM的操作和CSS選擇器的語法。
我個人比較傾向將網頁的功能類比於Powerpoint、Keynote、Impress...這類簡報軟體,它可以容納各式各樣媒體,像是文字、圖片、影片、音樂…等,可以幫這些媒體進行排版工作,也可以製作動畫。
當然簡報軟體具備WYSIWYG(what you see is what you get)的所見即所得特性,又有大量的圖形介面,可以利用滑鼠選擇屬性的設定值,對一般人學習比較容易理解,大大的降低了軟體的學習難度。而網頁則需要將HTML、CSS和Javascript三個元素交由網頁瀏覽器解析後,再將畫面呈現出來,學習門檻高了很多。在可程式化的部份,簡報軟體大多可由VBA來操控簡報軟體的物件,來進行一些自動化的工作;而網頁則依賴Javascript這個程式語言和HTML的DOM來進行自動化的工作。無論是簡報軟體或網頁對一般使用者的學習難度都相當的高。
就目前這樣分析,簡報系統在使用上是優於網頁,目前現況也是如此,但是簡報軟體還是有一些潛在性的缺點。
基於這個原因,筆者才借鐵人賽這個機會介紹JSXGraph這個套件,希望具有簡單程式設計的數學老師,在簡略的學習網頁後,能設計出可在上課中實用的教學網頁。接下來會以完成範例為目標,用最精簡的方式介紹Html、DOM和Css選擇器。
<h2 class="title">尤拉線定理</h1>
<div class="container">
<div id="box" class="jxgbox" style="width: 500px;height: 500px;"></div>
<div class="btnContainer">
<div class="btns">
<button type="button" class="btn medians">顯示中線</button>
<button type="button" class="btn centroid">顯示重心</button>
<button type="button" class="btn biperpendiculars">顯示中垂線</button>
<button type="button" class="btn circumcentre">顯示外心</button>
<button type="button" class="btn altitudes">顯示高</button>
<button type="button" class="btn orthocentre">顯示垂心</button>
<button type="button" class="btn Eulerline">顯示尤拉線</button>
</div>
</div>
</div>
一個class可以有多個值,瀏覽器會存在陣列中。
HTML(HyperText Markup Language),也就是超文本標記語言,是可延伸標記語言XML(Extensible Markup Language)的一種,因此我們可以將它的文件建立成一個樹狀結構圖,如上例的HTML碼就可以建成下圖:
這個樹狀結構就稱為DOM,DOM是Document Object Model的縮寫,上下的節點關係是父子節點,同屬一個父節點,即為兄弟節點。DOM中每個節點(node)都有各自的屬性,像id、class、style、src…等等,每個屬性也有各自的功能。其中id屬性不可重複,可以唯一識別節點;而class通常作為CSS選擇器選擇節點用,可以在style.css中撰寫css用,許多編輯器中也提供CSS選擇快捷寫出html檔,也可以提供javascript操作DOM。javascript的document下有很多操作DOM的方法,為了簡單化,這邊就介紹querySelector和querySelectorAll兩個方法,這兩個方法都必須使用CSS選擇器,所以我們先說明CSS選擇器。
CSS的基本語法非常簡單,就是標籤[屬性="屬性值"]
,標籤和屬性值有些時候可省略,接下來介紹常用的選擇器。
#id值
,例如#box
可選擇下面節點。<div id="box" class="jxgbox" style="width: 500px;height: 500px;"></div>
.類別值
,例如.btn
可選擇下列節點。<button type="button" class="btn medians">顯示中線</button>
<button type="button" class="btn centroid">顯示重心</button>
<button type="button" class="btn biperpendiculars">顯示中垂線</button>
<button type="button" class="btn circumcentre">顯示外心</button>
<button type="button" class="btn altitudes">顯示高</button>
<button type="button" class="btn orthocentre">顯示垂心</button>
<button type="button" class="btn Eulerline">顯示尤拉線</button>
.container .btns
.container .btnContainer
我們會用的函式有下面幾個
常用的事件有
click
、dblclick
、keyup
、keydown
、mouseover
…等等
下面這段程式碼製作了可以切換三中線的顯示和顯藏的按鈕。
const btnMedians = document.querySelector('.medians')
btnMedians.addEventListener('click', () => {
showMedians = !showMedians
board.update()
if (showMedians) {
btnMedians.innerHTML = '隱藏中線'
} else {
btnMedians.innerHTML = '顯示中線'
}
})
箭頭函式不能使用
this
程式的結構和昨天使用JSXGraph內建的按鈕大同小異,因為這是在畫板外的按鈕,回呼函數要記得使用board.update()更新畫面。this
指得是觸發事件的節點,在這裏就是代表btnMedians
。我們可以用同樣的結構寫下其它七個按鈕的程式,程式碼連結在後面。
同樣的結構寫了七次,感覺有些冗長,我們將html的部分重新配置,像顯示中線的按鈕改成
<button class="btn" data-element="medians">顯示中線</button>
我們設置了data-element的屬性,在javascript中可以用this.dataset.element存取其中的內容。javascript中,我們刪去了showMedians…等變數,設置了elements的物件,並利用querySelectorAll('.btn')選取了所有包含btn class的button節點佇列(nodesList),forEach方法寫成簡潔的程式碼。
const elements = {
medians: {
title: '中線',
show: false,
},
biperpendiculars: {
title: '中垂線',
show: false,
},
altitudes: {
title: '高',
show: false,
},
centroid: {
title: '重心',
show: false,
},
circumcentre: {
title: '外心',
show: false,
},
orthocentre: {
title: '垂心',
show: false,
},
Eulerline: {
title: '尤拉線',
show: false
}
}
const medianAB = board.create('segment', [pointC, midpointAB], { visible: () => elements.medians.show })
// 替每個節點加入事件監聽
const btns = document.querySelectorAll('.btn')
btns.forEach(btn => {
btn.addEventListener('click', handleToggle)
})
// 監聽事件使用同一個監聽函數
function handleToggle(e) {
let ele = this.dataset.element
elements[ele].show = !elements[ele].show
board.update()
if (elements[ele].show) {
this.innerHTML = '隱藏' + elements[ele].title
this.style.background = '#37613C'
this.style.color = 'white'
this.style.borderColor = '#f0f0f0'
} else {
this.innerHTML = '顯示' + elements[ele].title
this.style.background = '#F0F0F0'
this.style.color = '#37613C'
this.style.borderColor = '#37613C'
}
}
因為所有的監聽都使用同一個監聽函數,我們沒有使用箭頭函式,因此可以使用
this
這個關鍵字,這裏this
也可以用e.currentTarget或e.target代替,這兩個略有不同,牽涉到DOM的Event Propagation,這邊就不多談了。
(https://replit.com/@yegc22/iThomeIronman2022Day7-1?v=1 )
程式碼將一些按鈕,滑桿獨立出來,可以讓版面更清爽,也寫了簡單的CSS做了按鈕的排版,也具備一些簡單的RWD效果。利用CSS可以做出美觀的UI介面,因應手機使用的趨勢,製作響應式設計(RWD:Responsive Web Design)的網頁畫面。接下來的幾天,我們就會介紹一些CSS排版的重要概念,並利用它們美化我們的介面。